# Author: Allen Hutchison
# Copyright (C) 2006 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#      Unless required by applicable law or agreed to in writing, software
#      distributed under the License is distributed on an "AS IS" BASIS,
#      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#      See the License for the specific language governing permissions and
#      limitations under the License.
#
# This package represents an actual test case inside of OAF. You can see
# this used in the suite and harness packages. It is also used in any
# results reporting agent that you write for the harness.

package Oaf::Test;
use base qw(Oaf);

use strict;
use warnings;

# new()
#  Create a new instance of an Oaf::Test
#  This is used by the Oaf::Suite object
#  when it parses a suite file to hand
#  off to the harness.
sub new {
  my($class, $test_line, @args) = @_;

  # Start with a base Oaf object
  my $self = $class->SUPER::new(@args);
  # Turn it into a test.
  bless $self, $class;

  # The test line should look something like this:
  # 0 /bin/ls -al /home/, and will come from a suite
  # file.
  if ($test_line =~ /^(\d+)\s+(\S+)\s*(.*)/) {
    $self->id($1);
    $self->test($2);
    $self->args($3);
  }

  return $self;
}

# Most methods in the test class are just used
# to access attributes. We'll set them all up
# through autoload.
my %passthrough = map {$_ => 1} qw/id args start_time end_time exit_code
				   pid output/;

sub AUTOLOAD {
  my($self, $arg) = @_;
  my $method = our $AUTOLOAD;
  $method =~ s/.*:://;
  return unless $method =~ /[^A-Z]/; # skip DESTROY and all-cap methods.
  $self->warning("invalid attribute method: $method")
    unless $passthrough{$method};
  $self->{uc $method} = $arg if defined($arg);
  return $self->{uc $method};
}

# duration()
#  Returns the time, in seconds, the test ran.
#  Will return one if start_time and end_time
#  are equal, and zero if the test hasn't been
#  run yet.
sub duration {
  my($self) = @_;
  my $start_time = $self->start_time();
  my $end_time = $self->end_time();

  unless (defined($start_time) and defined($end_time)) {
    return 0;
  }

  # All tests take at least a second because the harness
  # sleeps that long between tests. So, we return one
  # in this case.
  if ($start_time == $end_time) {
    return 1;
  } else {
    return $end_time - $start_time;
  }
}

# exit_code_string()
#  Returns a string saying test passed or failed
#  depending on the exit code of a particular test.
sub exit_code_string {
  my($self) = @_;
  my $exit_code = $self->exit_code();
  unless(defined($exit_code)) {
    return "No Exit Code Defined";
  } else {
    if ($exit_code == 0) {
      return "Test Passed";
    } else {
      return "Test Failed";
    }
  }
}

# test()
#  This is the path to the actual executable that the harness will
#  run.
sub test {
  my($self, $test) = @_;

  unless(defined($test)) {
    return $self->{'Test'};
  }

  # All tests should be a full path, but we allow
  # a shortcut in the suite file to tests that are
  # located in the scripts directory. In that case
  # the user can leave off the base path.
  unless($test =~ m{^/}) {
    my $base_path = $self->get_param('oaf', 'base_path');
    if (defined($base_path)) {
      $test = "$base_path/scripts/$test";
    }
  }

  if((-e $test) and (-x $test)) {
    $self->{'Test'} = $test;
    return $self->{'Test'};
  } else {
    $self->fatal_error("Can't figure out path or it isn't executable: $test");
  }
}

# start_time_stamp()
#  returns a formatted time stamp for when the test started.
sub start_time_stamp {
  my($self) = @_;
  return $self->time_stamp($self->start_time());
}

# end_time_stamp()
#  returns a formatted time stamp for when the test ended.
sub end_time_stamp {
  my($self) = @_;
  return $self->time_stamp($self->end_time());
}

# Have to eval to something
1;
__END__
